// K'_max as defined in section 5.1.2
pub const MAX_SOURCE_SYMBOLS_PER_BLOCK: u32 = 56403;

// Table 2, as defined in section 5.6
pub const SYSTEMATIC_INDICES_AND_PARAMETERS: [(u32, u32, u32, u32, u32); 477] = [
    (10, 254, 7, 10, 17),
    (12, 630, 7, 10, 19),
    (18, 682, 11, 10, 29),
    (20, 293, 11, 10, 31),
    (26, 80, 11, 10, 37),
    (30, 566, 11, 10, 41),
    (32, 860, 11, 10, 43),
    (36, 267, 11, 10, 47),
    (42, 822, 11, 10, 53),
    (46, 506, 13, 10, 59),
    (48, 589, 13, 10, 61),
    (49, 87, 13, 10, 61),
    (55, 520, 13, 10, 67),
    (60, 159, 13, 10, 71),
    (62, 235, 13, 10, 73),
    (69, 157, 13, 10, 79),
    (75, 502, 17, 10, 89),
    (84, 334, 17, 10, 97),
    (88, 583, 17, 10, 101),
    (91, 66, 17, 10, 103),
    (95, 352, 17, 10, 107),
    (97, 365, 17, 10, 109),
    (101, 562, 17, 10, 113),
    (114, 5, 19, 10, 127),
    (119, 603, 19, 10, 131),
    (125, 721, 19, 10, 137),
    (127, 28, 19, 10, 139),
    (138, 660, 19, 10, 149),
    (140, 829, 19, 10, 151),
    (149, 900, 23, 10, 163),
    (153, 930, 23, 10, 167),
    (160, 814, 23, 10, 173),
    (166, 661, 23, 10, 179),
    (168, 693, 23, 10, 181),
    (179, 780, 23, 10, 191),
    (181, 605, 23, 10, 193),
    (185, 551, 23, 10, 197),
    (187, 777, 23, 10, 199),
    (200, 491, 23, 10, 211),
    (213, 396, 23, 10, 223),
    (217, 764, 29, 10, 233),
    (225, 843, 29, 10, 241),
    (236, 646, 29, 10, 251),
    (242, 557, 29, 10, 257),
    (248, 608, 29, 10, 263),
    (257, 265, 29, 10, 271),
    (263, 505, 29, 10, 277),
    (269, 722, 29, 10, 283),
    (280, 263, 29, 10, 293),
    (295, 999, 29, 10, 307),
    (301, 874, 29, 10, 313),
    (305, 160, 29, 10, 317),
    (324, 575, 31, 10, 337),
    (337, 210, 31, 10, 349),
    (341, 513, 31, 10, 353),
    (347, 503, 31, 10, 359),
    (355, 558, 31, 10, 367),
    (362, 932, 31, 10, 373),
    (368, 404, 31, 10, 379),
    (372, 520, 37, 10, 389),
    (380, 846, 37, 10, 397),
    (385, 485, 37, 10, 401),
    (393, 728, 37, 10, 409),
    (405, 554, 37, 10, 421),
    (418, 471, 37, 10, 433),
    (428, 641, 37, 10, 443),
    (434, 732, 37, 10, 449),
    (447, 193, 37, 10, 461),
    (453, 934, 37, 10, 467),
    (466, 864, 37, 10, 479),
    (478, 790, 37, 10, 491),
    (486, 912, 37, 10, 499),
    (491, 617, 37, 10, 503),
    (497, 587, 37, 10, 509),
    (511, 800, 37, 10, 523),
    (526, 923, 41, 10, 541),
    (532, 998, 41, 10, 547),
    (542, 92, 41, 10, 557),
    (549, 497, 41, 10, 563),
    (557, 559, 41, 10, 571),
    (563, 667, 41, 10, 577),
    (573, 912, 41, 10, 587),
    (580, 262, 41, 10, 593),
    (588, 152, 41, 10, 601),
    (594, 526, 41, 10, 607),
    (600, 268, 41, 10, 613),
    (606, 212, 41, 10, 619),
    (619, 45, 41, 10, 631),
    (633, 898, 43, 10, 647),
    (640, 527, 43, 10, 653),
    (648, 558, 43, 10, 661),
    (666, 460, 47, 10, 683),
    (675, 5, 47, 10, 691),
    (685, 895, 47, 10, 701),
    (693, 996, 47, 10, 709),
    (703, 282, 47, 10, 719),
    (718, 513, 47, 10, 733),
    (728, 865, 47, 10, 743),
    (736, 870, 47, 10, 751),
    (747, 239, 47, 10, 761),
    (759, 452, 47, 10, 773),
    (778, 862, 53, 10, 797),
    (792, 852, 53, 10, 811),
    (802, 643, 53, 10, 821),
    (811, 543, 53, 10, 829),
    (821, 447, 53, 10, 839),
    (835, 321, 53, 10, 853),
    (845, 287, 53, 10, 863),
    (860, 12, 53, 10, 877),
    (870, 251, 53, 10, 887),
    (891, 30, 53, 10, 907),
    (903, 621, 53, 10, 919),
    (913, 555, 53, 10, 929),
    (926, 127, 53, 10, 941),
    (938, 400, 53, 10, 953),
    (950, 91, 59, 10, 971),
    (963, 916, 59, 10, 983),
    (977, 935, 59, 10, 997),
    (989, 691, 59, 10, 1009),
    (1002, 299, 59, 10, 1021),
    (1020, 282, 59, 10, 1039),
    (1032, 824, 59, 10, 1051),
    (1050, 536, 59, 11, 1069),
    (1074, 596, 59, 11, 1093),
    (1085, 28, 59, 11, 1103),
    (1099, 947, 59, 11, 1117),
    (1111, 162, 59, 11, 1129),
    (1136, 536, 59, 11, 1153),
    (1152, 1000, 61, 11, 1171),
    (1169, 251, 61, 11, 1187),
    (1183, 673, 61, 11, 1201),
    (1205, 559, 61, 11, 1223),
    (1220, 923, 61, 11, 1237),
    (1236, 81, 67, 11, 1259),
    (1255, 478, 67, 11, 1277),
    (1269, 198, 67, 11, 1291),
    (1285, 137, 67, 11, 1307),
    (1306, 75, 67, 11, 1327),
    (1347, 29, 67, 11, 1367),
    (1361, 231, 67, 11, 1381),
    (1389, 532, 67, 11, 1409),
    (1404, 58, 67, 11, 1423),
    (1420, 60, 67, 11, 1439),
    (1436, 964, 71, 11, 1459),
    (1461, 624, 71, 11, 1483),
    (1477, 502, 71, 11, 1499),
    (1502, 636, 71, 11, 1523),
    (1522, 986, 71, 11, 1543),
    (1539, 950, 71, 11, 1559),
    (1561, 735, 73, 11, 1583),
    (1579, 866, 73, 11, 1601),
    (1600, 203, 73, 11, 1621),
    (1616, 83, 73, 11, 1637),
    (1649, 14, 73, 11, 1669),
    (1673, 522, 79, 11, 1699),
    (1698, 226, 79, 11, 1723),
    (1716, 282, 79, 11, 1741),
    (1734, 88, 79, 11, 1759),
    (1759, 636, 79, 11, 1783),
    (1777, 860, 79, 11, 1801),
    (1800, 324, 79, 11, 1823),
    (1824, 424, 79, 11, 1847),
    (1844, 999, 79, 11, 1867),
    (1863, 682, 83, 11, 1889),
    (1887, 814, 83, 11, 1913),
    (1906, 979, 83, 11, 1931),
    (1926, 538, 83, 11, 1951),
    (1954, 278, 83, 11, 1979),
    (1979, 580, 83, 11, 2003),
    (2005, 773, 83, 11, 2029),
    (2040, 911, 89, 11, 2069),
    (2070, 506, 89, 11, 2099),
    (2103, 628, 89, 11, 2131),
    (2125, 282, 89, 11, 2153),
    (2152, 309, 89, 11, 2179),
    (2195, 858, 89, 11, 2221),
    (2217, 442, 89, 11, 2243),
    (2247, 654, 89, 11, 2273),
    (2278, 82, 97, 11, 2311),
    (2315, 428, 97, 11, 2347),
    (2339, 442, 97, 11, 2371),
    (2367, 283, 97, 11, 2399),
    (2392, 538, 97, 11, 2423),
    (2416, 189, 97, 11, 2447),
    (2447, 438, 97, 11, 2477),
    (2473, 912, 97, 11, 2503),
    (2502, 1, 97, 11, 2531),
    (2528, 167, 97, 11, 2557),
    (2565, 272, 97, 11, 2593),
    (2601, 209, 101, 11, 2633),
    (2640, 927, 101, 11, 2671),
    (2668, 386, 101, 11, 2699),
    (2701, 653, 101, 11, 2731),
    (2737, 669, 101, 11, 2767),
    (2772, 431, 101, 11, 2801),
    (2802, 793, 103, 11, 2833),
    (2831, 588, 103, 11, 2861),
    (2875, 777, 107, 11, 2909),
    (2906, 939, 107, 11, 2939),
    (2938, 864, 107, 11, 2971),
    (2979, 627, 107, 11, 3011),
    (3015, 265, 109, 11, 3049),
    (3056, 976, 109, 11, 3089),
    (3101, 988, 113, 11, 3137),
    (3151, 507, 113, 11, 3187),
    (3186, 640, 113, 11, 3221),
    (3224, 15, 113, 11, 3259),
    (3265, 667, 113, 11, 3299),
    (3299, 24, 127, 11, 3347),
    (3344, 877, 127, 11, 3391),
    (3387, 240, 127, 11, 3433),
    (3423, 720, 127, 11, 3469),
    (3466, 93, 127, 11, 3511),
    (3502, 919, 127, 11, 3547),
    (3539, 635, 127, 11, 3583),
    (3579, 174, 127, 11, 3623),
    (3616, 647, 127, 11, 3659),
    (3658, 820, 127, 11, 3701),
    (3697, 56, 127, 11, 3739),
    (3751, 485, 127, 11, 3793),
    (3792, 210, 127, 11, 3833),
    (3840, 124, 127, 11, 3881),
    (3883, 546, 127, 11, 3923),
    (3924, 954, 131, 11, 3967),
    (3970, 262, 131, 11, 4013),
    (4015, 927, 131, 11, 4057),
    (4069, 957, 131, 11, 4111),
    (4112, 726, 137, 11, 4159),
    (4165, 583, 137, 11, 4211),
    (4207, 782, 137, 11, 4253),
    (4252, 37, 137, 11, 4297),
    (4318, 758, 137, 11, 4363),
    (4365, 777, 137, 11, 4409),
    (4418, 104, 139, 11, 4463),
    (4468, 476, 139, 11, 4513),
    (4513, 113, 149, 11, 4567),
    (4567, 313, 149, 11, 4621),
    (4626, 102, 149, 11, 4679),
    (4681, 501, 149, 11, 4733),
    (4731, 332, 149, 11, 4783),
    (4780, 786, 149, 11, 4831),
    (4838, 99, 149, 11, 4889),
    (4901, 658, 149, 11, 4951),
    (4954, 794, 149, 11, 5003),
    (5008, 37, 151, 11, 5059),
    (5063, 471, 151, 11, 5113),
    (5116, 94, 157, 11, 5171),
    (5172, 873, 157, 11, 5227),
    (5225, 918, 157, 11, 5279),
    (5279, 945, 157, 11, 5333),
    (5334, 211, 157, 11, 5387),
    (5391, 341, 157, 11, 5443),
    (5449, 11, 163, 11, 5507),
    (5506, 578, 163, 11, 5563),
    (5566, 494, 163, 11, 5623),
    (5637, 694, 163, 11, 5693),
    (5694, 252, 163, 11, 5749),
    (5763, 451, 167, 11, 5821),
    (5823, 83, 167, 11, 5881),
    (5896, 689, 167, 11, 5953),
    (5975, 488, 173, 11, 6037),
    (6039, 214, 173, 11, 6101),
    (6102, 17, 173, 11, 6163),
    (6169, 469, 173, 11, 6229),
    (6233, 263, 179, 11, 6299),
    (6296, 309, 179, 11, 6361),
    (6363, 984, 179, 11, 6427),
    (6427, 123, 179, 11, 6491),
    (6518, 360, 179, 11, 6581),
    (6589, 863, 181, 11, 6653),
    (6655, 122, 181, 11, 6719),
    (6730, 522, 191, 11, 6803),
    (6799, 539, 191, 11, 6871),
    (6878, 181, 191, 11, 6949),
    (6956, 64, 191, 11, 7027),
    (7033, 387, 191, 11, 7103),
    (7108, 967, 191, 11, 7177),
    (7185, 843, 191, 11, 7253),
    (7281, 999, 193, 11, 7351),
    (7360, 76, 197, 11, 7433),
    (7445, 142, 197, 11, 7517),
    (7520, 599, 197, 11, 7591),
    (7596, 576, 199, 11, 7669),
    (7675, 176, 211, 11, 7759),
    (7770, 392, 211, 11, 7853),
    (7855, 332, 211, 11, 7937),
    (7935, 291, 211, 11, 8017),
    (8030, 913, 211, 11, 8111),
    (8111, 608, 211, 11, 8191),
    (8194, 212, 211, 11, 8273),
    (8290, 696, 211, 11, 8369),
    (8377, 931, 223, 11, 8467),
    (8474, 326, 223, 11, 8563),
    (8559, 228, 223, 11, 8647),
    (8654, 706, 223, 11, 8741),
    (8744, 144, 223, 11, 8831),
    (8837, 83, 223, 11, 8923),
    (8928, 743, 223, 11, 9013),
    (9019, 187, 223, 11, 9103),
    (9111, 654, 227, 11, 9199),
    (9206, 359, 227, 11, 9293),
    (9303, 493, 229, 11, 9391),
    (9400, 369, 233, 11, 9491),
    (9497, 981, 233, 11, 9587),
    (9601, 276, 239, 11, 9697),
    (9708, 647, 239, 11, 9803),
    (9813, 389, 239, 11, 9907),
    (9916, 80, 239, 11, 10009),
    (10017, 396, 241, 11, 10111),
    (10120, 580, 251, 11, 10223),
    (10241, 873, 251, 11, 10343),
    (10351, 15, 251, 11, 10453),
    (10458, 976, 251, 11, 10559),
    (10567, 584, 251, 11, 10667),
    (10676, 267, 257, 11, 10781),
    (10787, 876, 257, 11, 10891),
    (10899, 642, 257, 12, 11003),
    (11015, 794, 257, 12, 11119),
    (11130, 78, 263, 12, 11239),
    (11245, 736, 263, 12, 11353),
    (11358, 882, 269, 12, 11471),
    (11475, 251, 269, 12, 11587),
    (11590, 434, 269, 12, 11701),
    (11711, 204, 269, 12, 11821),
    (11829, 256, 271, 12, 11941),
    (11956, 106, 277, 12, 12073),
    (12087, 375, 277, 12, 12203),
    (12208, 148, 277, 12, 12323),
    (12333, 496, 281, 12, 12451),
    (12460, 88, 281, 12, 12577),
    (12593, 826, 293, 12, 12721),
    (12726, 71, 293, 12, 12853),
    (12857, 925, 293, 12, 12983),
    (13002, 760, 293, 12, 13127),
    (13143, 130, 293, 12, 13267),
    (13284, 641, 307, 12, 13421),
    (13417, 400, 307, 12, 13553),
    (13558, 480, 307, 12, 13693),
    (13695, 76, 307, 12, 13829),
    (13833, 665, 307, 12, 13967),
    (13974, 910, 307, 12, 14107),
    (14115, 467, 311, 12, 14251),
    (14272, 964, 311, 12, 14407),
    (14415, 625, 313, 12, 14551),
    (14560, 362, 317, 12, 14699),
    (14713, 759, 317, 12, 14851),
    (14862, 728, 331, 12, 15013),
    (15011, 343, 331, 12, 15161),
    (15170, 113, 331, 12, 15319),
    (15325, 137, 331, 12, 15473),
    (15496, 308, 331, 12, 15643),
    (15651, 800, 337, 12, 15803),
    (15808, 177, 337, 12, 15959),
    (15977, 961, 337, 12, 16127),
    (16161, 958, 347, 12, 16319),
    (16336, 72, 347, 12, 16493),
    (16505, 732, 347, 12, 16661),
    (16674, 145, 349, 12, 16831),
    (16851, 577, 353, 12, 17011),
    (17024, 305, 353, 12, 17183),
    (17195, 50, 359, 12, 17359),
    (17376, 351, 359, 12, 17539),
    (17559, 175, 367, 12, 17729),
    (17742, 727, 367, 12, 17911),
    (17929, 902, 367, 12, 18097),
    (18116, 409, 373, 12, 18289),
    (18309, 776, 373, 12, 18481),
    (18503, 586, 379, 12, 18679),
    (18694, 451, 379, 12, 18869),
    (18909, 287, 383, 12, 19087),
    (19126, 246, 389, 12, 19309),
    (19325, 222, 389, 12, 19507),
    (19539, 563, 397, 12, 19727),
    (19740, 839, 397, 12, 19927),
    (19939, 897, 401, 12, 20129),
    (20152, 409, 401, 12, 20341),
    (20355, 618, 409, 12, 20551),
    (20564, 439, 409, 12, 20759),
    (20778, 95, 419, 13, 20983),
    (20988, 448, 419, 13, 21191),
    (21199, 133, 419, 13, 21401),
    (21412, 938, 419, 13, 21613),
    (21629, 423, 431, 13, 21841),
    (21852, 90, 431, 13, 22063),
    (22073, 640, 431, 13, 22283),
    (22301, 922, 433, 13, 22511),
    (22536, 250, 439, 13, 22751),
    (22779, 367, 439, 13, 22993),
    (23010, 447, 443, 13, 23227),
    (23252, 559, 449, 13, 23473),
    (23491, 121, 457, 13, 23719),
    (23730, 623, 457, 13, 23957),
    (23971, 450, 457, 13, 24197),
    (24215, 253, 461, 13, 24443),
    (24476, 106, 467, 13, 24709),
    (24721, 863, 467, 13, 24953),
    (24976, 148, 479, 13, 25219),
    (25230, 427, 479, 13, 25471),
    (25493, 138, 479, 13, 25733),
    (25756, 794, 487, 13, 26003),
    (26022, 247, 487, 13, 26267),
    (26291, 562, 491, 13, 26539),
    (26566, 53, 499, 13, 26821),
    (26838, 135, 499, 13, 27091),
    (27111, 21, 503, 13, 27367),
    (27392, 201, 509, 13, 27653),
    (27682, 169, 521, 13, 27953),
    (27959, 70, 521, 13, 28229),
    (28248, 386, 521, 13, 28517),
    (28548, 226, 523, 13, 28817),
    (28845, 3, 541, 13, 29131),
    (29138, 769, 541, 13, 29423),
    (29434, 590, 541, 13, 29717),
    (29731, 672, 541, 13, 30013),
    (30037, 713, 547, 13, 30323),
    (30346, 967, 547, 13, 30631),
    (30654, 368, 557, 14, 30949),
    (30974, 348, 557, 14, 31267),
    (31285, 119, 563, 14, 31583),
    (31605, 503, 569, 14, 31907),
    (31948, 181, 571, 14, 32251),
    (32272, 394, 577, 14, 32579),
    (32601, 189, 587, 14, 32917),
    (32932, 210, 587, 14, 33247),
    (33282, 62, 593, 14, 33601),
    (33623, 273, 593, 14, 33941),
    (33961, 554, 599, 14, 34283),
    (34302, 936, 607, 14, 34631),
    (34654, 483, 607, 14, 34981),
    (35031, 397, 613, 14, 35363),
    (35395, 241, 619, 14, 35731),
    (35750, 500, 631, 14, 36097),
    (36112, 12, 631, 14, 36457),
    (36479, 958, 641, 14, 36833),
    (36849, 524, 641, 14, 37201),
    (37227, 8, 643, 14, 37579),
    (37606, 100, 653, 14, 37967),
    (37992, 339, 653, 14, 38351),
    (38385, 804, 659, 14, 38749),
    (38787, 510, 673, 14, 39163),
    (39176, 18, 673, 14, 39551),
    (39576, 412, 677, 14, 39953),
    (39980, 394, 683, 14, 40361),
    (40398, 830, 691, 15, 40787),
    (40816, 535, 701, 15, 41213),
    (41226, 199, 701, 15, 41621),
    (41641, 27, 709, 15, 42043),
    (42067, 298, 709, 15, 42467),
    (42490, 368, 719, 15, 42899),
    (42916, 755, 727, 15, 43331),
    (43388, 379, 727, 15, 43801),
    (43840, 73, 733, 15, 44257),
    (44279, 387, 739, 15, 44701),
    (44729, 457, 751, 15, 45161),
    (45183, 761, 751, 15, 45613),
    (45638, 855, 757, 15, 46073),
    (46104, 370, 769, 15, 46549),
    (46574, 261, 769, 15, 47017),
    (47047, 299, 787, 15, 47507),
    (47523, 920, 787, 15, 47981),
    (48007, 269, 787, 15, 48463),
    (48489, 862, 797, 15, 48953),
    (48976, 349, 809, 15, 49451),
    (49470, 103, 809, 15, 49943),
    (49978, 115, 821, 15, 50461),
    (50511, 93, 821, 16, 50993),
    (51017, 982, 827, 16, 51503),
    (51530, 432, 839, 16, 52027),
    (52062, 340, 853, 16, 52571),
    (52586, 173, 853, 16, 53093),
    (53114, 421, 857, 16, 53623),
    (53650, 330, 863, 16, 54163),
    (54188, 624, 877, 16, 54713),
    (54735, 233, 877, 16, 55259),
    (55289, 362, 883, 16, 55817),
    (55843, 963, 907, 16, 56393),
    (56403, 471, 907, 16, 56951),
];

const P1_TABLE: [(u32, u32); 477] = [
    (10, 11),
    (12, 11),
    (18, 11),
    (20, 11),
    (26, 11),
    (30, 11),
    (32, 11),
    (36, 11),
    (42, 11),
    (46, 11),
    (48, 11),
    (49, 11),
    (55, 11),
    (60, 13),
    (62, 13),
    (69, 13),
    (75, 13),
    (84, 17),
    (88, 17),
    (91, 17),
    (95, 17),
    (97, 17),
    (101, 17),
    (114, 17),
    (119, 17),
    (125, 17),
    (127, 17),
    (138, 19),
    (140, 19),
    (149, 19),
    (153, 19),
    (160, 23),
    (166, 23),
    (168, 23),
    (179, 23),
    (181, 23),
    (185, 23),
    (187, 23),
    (200, 23),
    (213, 23),
    (217, 23),
    (225, 23),
    (236, 29),
    (242, 29),
    (248, 29),
    (257, 29),
    (263, 29),
    (269, 29),
    (280, 29),
    (295, 29),
    (301, 29),
    (305, 29),
    (324, 29),
    (337, 29),
    (341, 29),
    (347, 29),
    (355, 29),
    (362, 31),
    (368, 31),
    (372, 31),
    (380, 31),
    (385, 31),
    (393, 31),
    (405, 31),
    (418, 37),
    (428, 37),
    (434, 37),
    (447, 37),
    (453, 37),
    (466, 37),
    (478, 37),
    (486, 37),
    (491, 37),
    (497, 37),
    (511, 37),
    (526, 37),
    (532, 37),
    (542, 37),
    (549, 37),
    (557, 37),
    (563, 37),
    (573, 37),
    (580, 41),
    (588, 41),
    (594, 41),
    (600, 41),
    (606, 41),
    (619, 41),
    (633, 41),
    (640, 41),
    (648, 41),
    (666, 41),
    (675, 41),
    (685, 41),
    (693, 41),
    (703, 41),
    (718, 43),
    (728, 43),
    (736, 43),
    (747, 43),
    (759, 43),
    (778, 47),
    (792, 47),
    (802, 47),
    (811, 47),
    (821, 47),
    (835, 47),
    (845, 47),
    (860, 47),
    (870, 47),
    (891, 47),
    (903, 47),
    (913, 47),
    (926, 53),
    (938, 53),
    (950, 53),
    (963, 53),
    (977, 53),
    (989, 53),
    (1002, 53),
    (1020, 53),
    (1032, 53),
    (1050, 53),
    (1074, 53),
    (1085, 53),
    (1099, 53),
    (1111, 53),
    (1136, 53),
    (1152, 53),
    (1169, 59),
    (1183, 59),
    (1205, 59),
    (1220, 59),
    (1236, 59),
    (1255, 59),
    (1269, 59),
    (1285, 59),
    (1306, 59),
    (1347, 59),
    (1361, 59),
    (1389, 59),
    (1404, 59),
    (1420, 59),
    (1436, 59),
    (1461, 61),
    (1477, 61),
    (1502, 61),
    (1522, 61),
    (1539, 67),
    (1561, 67),
    (1579, 67),
    (1600, 67),
    (1616, 67),
    (1649, 67),
    (1673, 67),
    (1698, 67),
    (1716, 67),
    (1734, 67),
    (1759, 67),
    (1777, 67),
    (1800, 67),
    (1824, 67),
    (1844, 67),
    (1863, 71),
    (1887, 71),
    (1906, 71),
    (1926, 71),
    (1954, 71),
    (1979, 71),
    (2005, 71),
    (2040, 71),
    (2070, 71),
    (2103, 73),
    (2125, 73),
    (2152, 73),
    (2195, 79),
    (2217, 79),
    (2247, 79),
    (2278, 79),
    (2315, 79),
    (2339, 79),
    (2367, 79),
    (2392, 79),
    (2416, 79),
    (2447, 79),
    (2473, 79),
    (2502, 79),
    (2528, 79),
    (2565, 83),
    (2601, 83),
    (2640, 83),
    (2668, 83),
    (2701, 83),
    (2737, 83),
    (2772, 83),
    (2802, 83),
    (2831, 89),
    (2875, 89),
    (2906, 89),
    (2938, 89),
    (2979, 89),
    (3015, 89),
    (3056, 89),
    (3101, 89),
    (3151, 89),
    (3186, 89),
    (3224, 89),
    (3265, 97),
    (3299, 97),
    (3344, 97),
    (3387, 97),
    (3423, 97),
    (3466, 97),
    (3502, 97),
    (3539, 97),
    (3579, 97),
    (3616, 97),
    (3658, 97),
    (3697, 97),
    (3751, 97),
    (3792, 97),
    (3840, 97),
    (3883, 101),
    (3924, 101),
    (3970, 101),
    (4015, 101),
    (4069, 101),
    (4112, 101),
    (4165, 103),
    (4207, 103),
    (4252, 103),
    (4318, 103),
    (4365, 107),
    (4418, 107),
    (4468, 107),
    (4513, 107),
    (4567, 107),
    (4626, 107),
    (4681, 109),
    (4731, 109),
    (4780, 109),
    (4838, 109),
    (4901, 113),
    (4954, 113),
    (5008, 113),
    (5063, 113),
    (5116, 113),
    (5172, 113),
    (5225, 127),
    (5279, 127),
    (5334, 127),
    (5391, 127),
    (5449, 127),
    (5506, 127),
    (5566, 127),
    (5637, 127),
    (5694, 127),
    (5763, 127),
    (5823, 127),
    (5896, 127),
    (5975, 127),
    (6039, 127),
    (6102, 127),
    (6169, 127),
    (6233, 127),
    (6296, 127),
    (6363, 127),
    (6427, 127),
    (6518, 127),
    (6589, 131),
    (6655, 131),
    (6730, 131),
    (6799, 131),
    (6878, 131),
    (6956, 131),
    (7033, 137),
    (7108, 137),
    (7185, 137),
    (7281, 137),
    (7360, 137),
    (7445, 137),
    (7520, 137),
    (7596, 137),
    (7675, 139),
    (7770, 139),
    (7855, 149),
    (7935, 149),
    (8030, 149),
    (8111, 149),
    (8194, 149),
    (8290, 149),
    (8377, 149),
    (8474, 149),
    (8559, 149),
    (8654, 149),
    (8744, 149),
    (8837, 149),
    (8928, 149),
    (9019, 151),
    (9111, 151),
    (9206, 151),
    (9303, 157),
    (9400, 157),
    (9497, 157),
    (9601, 157),
    (9708, 157),
    (9813, 157),
    (9916, 157),
    (10017, 163),
    (10120, 163),
    (10241, 163),
    (10351, 163),
    (10458, 163),
    (10567, 163),
    (10676, 163),
    (10787, 167),
    (10899, 167),
    (11015, 167),
    (11130, 167),
    (11245, 167),
    (11358, 173),
    (11475, 173),
    (11590, 173),
    (11711, 173),
    (11829, 173),
    (11956, 173),
    (12087, 173),
    (12208, 179),
    (12333, 179),
    (12460, 179),
    (12593, 179),
    (12726, 179),
    (12857, 179),
    (13002, 181),
    (13143, 181),
    (13284, 191),
    (13417, 191),
    (13558, 191),
    (13695, 191),
    (13833, 191),
    (13974, 191),
    (14115, 191),
    (14272, 191),
    (14415, 191),
    (14560, 191),
    (14713, 191),
    (14862, 193),
    (15011, 193),
    (15170, 197),
    (15325, 197),
    (15496, 197),
    (15651, 197),
    (15808, 199),
    (15977, 199),
    (16161, 211),
    (16336, 211),
    (16505, 211),
    (16674, 211),
    (16851, 211),
    (17024, 211),
    (17195, 211),
    (17376, 211),
    (17559, 211),
    (17742, 211),
    (17929, 211),
    (18116, 223),
    (18309, 223),
    (18503, 223),
    (18694, 223),
    (18909, 223),
    (19126, 223),
    (19325, 223),
    (19539, 223),
    (19740, 223),
    (19939, 223),
    (20152, 227),
    (20355, 227),
    (20564, 227),
    (20778, 227),
    (20988, 229),
    (21199, 233),
    (21412, 233),
    (21629, 233),
    (21852, 233),
    (22073, 239),
    (22301, 239),
    (22536, 239),
    (22779, 239),
    (23010, 239),
    (23252, 241),
    (23491, 251),
    (23730, 251),
    (23971, 251),
    (24215, 251),
    (24476, 251),
    (24721, 251),
    (24976, 251),
    (25230, 251),
    (25493, 257),
    (25756, 257),
    (26022, 257),
    (26291, 257),
    (26566, 257),
    (26838, 263),
    (27111, 263),
    (27392, 263),
    (27682, 263),
    (27959, 269),
    (28248, 269),
    (28548, 269),
    (28845, 269),
    (29138, 269),
    (29434, 271),
    (29731, 277),
    (30037, 277),
    (30346, 277),
    (30654, 277),
    (30974, 281),
    (31285, 281),
    (31605, 281),
    (31948, 283),
    (32272, 293),
    (32601, 293),
    (32932, 293),
    (33282, 293),
    (33623, 293),
    (33961, 293),
    (34302, 293),
    (34654, 307),
    (35031, 307),
    (35395, 307),
    (35750, 307),
    (36112, 307),
    (36479, 307),
    (36849, 307),
    (37227, 307),
    (37606, 307),
    (37992, 311),
    (38385, 311),
    (38787, 311),
    (39176, 313),
    (39576, 317),
    (39980, 317),
    (40398, 317),
    (40816, 331),
    (41226, 331),
    (41641, 331),
    (42067, 331),
    (42490, 331),
    (42916, 331),
    (43388, 331),
    (43840, 331),
    (44279, 337),
    (44729, 337),
    (45183, 337),
    (45638, 337),
    (46104, 347),
    (46574, 347),
    (47047, 347),
    (47523, 347),
    (48007, 347),
    (48489, 349),
    (48976, 349),
    (49470, 353),
    (49978, 353),
    (50511, 359),
    (51017, 359),
    (51530, 359),
    (52062, 367),
    (52586, 367),
    (53114, 367),
    (53650, 367),
    (54188, 373),
    (54735, 373),
    (55289, 373),
    (55843, 373),
    (56403, 379),
];

// Calculates, K', the extended source block size, in symbols, for a given source block size
// See section 5.3.1
pub fn extended_source_block_symbols(source_block_symbols: u32) -> u32 {
    assert!(source_block_symbols <= MAX_SOURCE_SYMBOLS_PER_BLOCK);
    for &(block_size, _, _, _, _) in SYSTEMATIC_INDICES_AND_PARAMETERS.iter() {
        if block_size >= source_block_symbols {
            return block_size;
        }
    }
    unreachable!();
}

// Calculates, J(K'), the systematic index, for a given number of source block symbols
// See section 5.6
pub fn systematic_index(source_block_symbols: u32) -> u32 {
    assert!(source_block_symbols <= MAX_SOURCE_SYMBOLS_PER_BLOCK);
    for &(block_size, systematic_index, _, _, _) in SYSTEMATIC_INDICES_AND_PARAMETERS.iter() {
        if block_size >= source_block_symbols {
            return systematic_index;
        }
    }
    unreachable!();
}

// Calculates, H(K'), the number of HDPC symbols, for a given number of source block symbols
// See section 5.6
pub fn num_hdpc_symbols(source_block_symbols: u32) -> u32 {
    assert!(source_block_symbols <= MAX_SOURCE_SYMBOLS_PER_BLOCK);
    for &(block_size, _, _, hdpc_symbols, _) in SYSTEMATIC_INDICES_AND_PARAMETERS.iter() {
        if block_size >= source_block_symbols {
            return hdpc_symbols;
        }
    }
    unreachable!();
}

// Calculates, S(K'), the number of LDPC symbols, for a given number of source block symbols
// See section 5.6
pub fn num_ldpc_symbols(source_block_symbols: u32) -> u32 {
    assert!(source_block_symbols <= MAX_SOURCE_SYMBOLS_PER_BLOCK);
    for &(block_size, _, ldpc_symbols, _, _) in SYSTEMATIC_INDICES_AND_PARAMETERS.iter() {
        if block_size >= source_block_symbols {
            return ldpc_symbols;
        }
    }
    unreachable!();
}

// Calculates, W(K'), the number of LT symbols, for a given number of source block symbols
// See section 5.6
pub fn num_lt_symbols(source_block_symbols: u32) -> u32 {
    assert!(source_block_symbols <= MAX_SOURCE_SYMBOLS_PER_BLOCK);
    for &(block_size, _, _, _, lt_symbols) in SYSTEMATIC_INDICES_AND_PARAMETERS.iter() {
        if block_size >= source_block_symbols {
            return lt_symbols;
        }
    }
    unreachable!();
}

// Calculates, L, the number of intermediate symbols, for a given number of source block symbols
// See section 5.3.3.3
pub fn num_intermediate_symbols(source_block_symbols: u32) -> u32 {
    extended_source_block_symbols(source_block_symbols)
        + num_ldpc_symbols(source_block_symbols)
        + num_hdpc_symbols(source_block_symbols)
}

// Calculates, P, the number of PI symbols, for a given number of source block symbols
// See section 5.3.3.3
pub fn num_pi_symbols(source_block_symbols: u32) -> u32 {
    num_intermediate_symbols(source_block_symbols) - num_lt_symbols(source_block_symbols)
}

// Calculates P1, smallest prime greater than P. See 5.3.3.3
pub fn calculate_p1(source_block_symbols: u32) -> u32 {
    assert!(source_block_symbols <= MAX_SOURCE_SYMBOLS_PER_BLOCK);
    for &(block_size, p1) in P1_TABLE.iter() {
        if block_size >= source_block_symbols {
            return p1;
        }
    }
    unreachable!();
}

#[cfg(test)]
mod tests {
    use crate::systematic_constants::num_ldpc_symbols;
    use crate::systematic_constants::num_lt_symbols;
    use crate::systematic_constants::{calculate_p1, num_pi_symbols, MAX_SOURCE_SYMBOLS_PER_BLOCK};

    #[test]
    fn all_prime() {
        for i in 0..=MAX_SOURCE_SYMBOLS_PER_BLOCK {
            // See section 5.6
            assert!(primal::is_prime(num_ldpc_symbols(i) as u64));
            assert!(primal::is_prime(num_lt_symbols(i) as u64));
        }
    }

    #[test]
    fn check_p1() {
        for i in 0..=MAX_SOURCE_SYMBOLS_PER_BLOCK {
            let mut p1 = num_pi_symbols(i);
            while !primal::is_prime(p1 as u64) {
                if p1 % 2 == 0 {
                    p1 += 1;
                } else {
                    p1 += 2;
                }
            }

            assert_eq!(p1, calculate_p1(i));
        }
    }
}
